/*
 * WorkUdpApi.cpp
 *
 *  Created on: 2017-6-23
 *      Author: root
 */
#include"WorkConnectApi.h"
#include"PublicLog.h"
#include"WorkPriApi.h"
#include"WorkPingApi.h"
#if USE_PUBLIC_UDP
#include"PublicNetHead.h"
#include<errno.h>
//初始化PING风格
UDPFLAG InitUdpFlag(){
    UDPFLAG flag={0};
    flag.PerListTime=1000;
    flag.PerNum=20;
    flag.PerTime=1000;
    flag.SendTimes=5;
    strcpy(flag.SrcIP,"0.0.0.0");
    return flag;
}
//显示PING风格
void ShowUdpFlag(UDPFLAG flag,size_t num){
    INFO("数量:%zd 总次数:%d 发送间隔:%d us 单次数量:%d 构建间隔:%d ms 源IP:%s",
    num,flag.SendTimes,flag.PerTime,flag.PerNum,flag.PerListTime,flag.SrcIP);

}
MAPCONNECTRESULTINFO GetUdpingByIPList(SETIPLIST IPList,SETIDLIST PortList,int bReuse){
    MAPCONNECTRESULTINFO result;
    UDPFLAG flag=InitUdpFlag();
    INFO("IP数量:%zd 端口数量:%zd",IPList.size(),PortList.size());
    SETIDLIST::iterator itport=PortList.begin();
    while(itport!=PortList.end()){
      int Port=*itport;
      SETCONNECTINFO connectlist;
      SETIPLIST::iterator itip=IPList.begin();
      while(itip!=IPList.end()){
        CONNECTKEY keyinfo;
        memset(&keyinfo,0,sizeof(CONNECTKEY));
        strcpy(keyinfo.IP,itip->c_str());
        keyinfo.Port=Port;
        connectlist.insert(keyinfo);
        itip++;
        }
      INFO("当前遍历端口:%d IP数量:%zd",Port,IPList.size());
      MAPCONNECTRESULTINFO tmp=GetUdpInfoByIPList(connectlist,flag);
      MAPCONNECTRESULTINFO::iterator it=tmp.begin();
      while(it!=tmp.end()){
        if(bReuse){
           result.insert(std::pair<CONNECTKEY,int>(it->first,it->second));
        }else{
           if(it->second>0){
              result.insert(std::pair<CONNECTKEY,int>(it->first,it->second));
              IPList.erase(it->first.IP);
               }
           }
        it++;
        }
      itport++;
       }
     return result;
}
MAPCONNECTRESULTINFO GetUdpInfoByIPListWithLocal(SETCONNECTINFO IPList,UDPFLAG flag){
    SETIPLIST publiclist=GetPublicIPList();
    MAPCONNECTRESULTINFO result;
    if(publiclist.size()<2){
		result=GetUdpInfoByIPList(IPList,flag);
    }else{
		SETIPLIST::iterator it=publiclist.begin();
		while(it!=publiclist.end()){
			strcpy(flag.SrcIP,it->c_str());
			MAPCONNECTRESULTINFO tmp=GetUdpInfoByIPList(IPList,flag);
			MAPCONNECTRESULTINFO::iterator it2=tmp.begin();
			while(it2!=tmp.end()){
				if(it2->second>0){
					IPList.erase(it2->first);
				}
				MAPCONNECTRESULTINFO::iterator it3=result.find(it2->first);
				if(it3==result.end()){
					result.insert(std::pair<CONNECTKEY,int>(it2->first,it2->second));
				}else{
					if(it2->second>0&&it2->second>it3->second){
						it3->second=it2->second;
					}
				}
				it2++;
			}
			it++;
        }
    }
    return result;
}
MAPCONNECTRESULTINFO GetUdpInfoByIPList(SETCONNECTINFO IPList,UDPFLAG flag){
    MAPCONNECTRESULTINFO result;
    ShowUdpFlag(flag,IPList.size());
    if(IPList.empty()){
       INFO("UDP 数量:%zd 为空 源IP:%s",IPList.size(),flag.SrcIP);
       return result;
     }
    int             sendflag=1;//发送标志
    int             checkflag=0;//检测标志
    int             makeflag=0;//构建标志
    int             sendtimes=0;
    struct timeval  sendtimestamp={0,0};
    struct timeval  checktimestamp={0,0};
    struct timeval  maketimestamp={0,0};
    int             sendnum=0;
    SETCONNECTINFO IPListTmp;
    gettimeofday(&sendtimestamp,NULL);
    checktimestamp=sendtimestamp;
    maketimestamp =sendtimestamp;
    int udp_sock=CreateUDPSocket(flag.PerTime,flag.SrcIP);
    if(udp_sock==-1){
		WRONG("Create UDP Socket Error!!!");
    }

    int icmp_sock=CreateICMPSocketUDP(flag.PerTime);
    if(icmp_sock==-1){
		close(udp_sock);
		WRONG("Create ICMP Socket Error!!!");
    }
    while((sendtimes<flag.SendTimes)&&(IPList.empty()==false)){
		if((makeflag==1)&&(IPListTmp.empty()==true)){
			sendtimes++;
			if(sendtimes<flag.SendTimes){
				IPListTmp=IPList;
				makeflag=0;
				gettimeofday(&maketimestamp,NULL);
            }
        }
//队列判断
		while((sendflag==1)&&(IPListTmp.empty()==false)){
			SETCONNECTINFO::iterator it=IPListTmp.begin();
			struct sockaddr_in dest_addr={0};
			dest_addr.sin_family=AF_INET;
			dest_addr.sin_addr.s_addr=inet_addr(it->IP);
			dest_addr.sin_port=htons(it->Port);
			IPListTmp.erase(it);
			sendto(udp_sock,"a",1,0,(struct sockaddr*)&dest_addr,sizeof(dest_addr));
         //printf("Ret:%d IP:%s Port:%hu Errno:%d\n",ret,it->IP,it->Port,errno);
			sendflag=0;
			if(sendnum<flag.PerNum){
				sendflag=1;
				continue;
            }
			sendnum=0;
        }
//队列检测
		do{
			CONNECTKEY key={"",0};
			int usetime=ReadICMPUDPPacket(icmp_sock,&key);
			if(usetime==1){
				if(IPList.find(key)!=IPList.end()){
					result.insert(std::pair<CONNECTKEY,int>(key,1));
					IPList.erase(key);
				}
			}else
			if(usetime!=-11)
				continue;
			break;
		}while(1);
//转h
		do{
			struct timeval timestamp;
			gettimeofday(&timestamp,NULL);
			if(GetTimerSubCommon(timestamp,checktimestamp)>1000){
				checktimestamp=timestamp;
				checkflag=1;
				sendflag=0;
			}else
			if(GetTimerSubCommonEx(timestamp,sendtimestamp)>flag.PerTime){
				sendflag=1;
				if(IPListTmp.empty()==true){
					if(GetTimerSubCommon(timestamp,maketimestamp)>flag.PerListTime){
						makeflag=1;
                    }
                }
            }
		}while(0);
//检测超时队列
		if(checkflag){
			checkflag=0;
			INFO("%ld.%06ld 进行一次UDP超时检测 发送剩余:%zd 发送进度:%d 已确认数量:%zd",
			checktimestamp.tv_sec,checktimestamp.tv_usec,
			IPListTmp.size(),sendtimes,result.size());
        }
    }
    close(udp_sock);
    close(icmp_sock);
    SETCONNECTINFO::iterator it=IPList.begin();
    while(it!=IPList.end()){
		result.insert(std::pair<CONNECTKEY,int>(*it,0));
		it++;
    }
    return result;
}
#endif
